# -*- coding: utf-8 -*-

"""120. 三角形最小路径和
给定一个三角形 triangle ，找出自顶向下的最小路径和。
每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说，如果正位于当前行的下标 i ，那么下一步可以移动到下一行的下标 i 或 i + 1 。

示例 1：
输入：triangle = [[2],[3,4],[6,5,7],[4,1,8,3]]
输出：11
解释：如下面简图所示：
   2
  3 4
 6 5 7
4 1 8 3
自顶向下的最小路径和为 11（即，2 + 3 + 5 + 1 = 11）。

示例 2：
输入：triangle = [[-10]]
输出：-10

提示：
1 <= triangle.length <= 200
triangle[0].length == 1
triangle[i].length == triangle[i - 1].length + 1
-104 <= triangle[i][j] <= 10^4

进阶：
你可以只使用 O(n) 的额外空间（n 为三角形的总行数）来解决这个问题吗？"""

class Solution:
    """
    定义：f(l, n) 为计算到达第 l 层，第 n 个位置的最小路径和
    递归基础：
        f(x, 0), f(x, last) 每行第一个这个排列是前缀和，每行最后一个这个排列也是前缀和
    递归定义：
        f(l, n) = min(f(l-1, n-1), f(l-1, n)) + triangle[l][n]

    将递归的计算过成，按动态规划，转换为递推的状态转义过程。
    """
    def minimumTotal(self, triangle: list) -> int:
        if len(triangle) == 1:
            return triangle[0][0]

        hight = len(triangle)
        l = 1
        while l < hight:
            count = len(triangle[l])
            triangle[l][0] += triangle[l-1][0]
            triangle[l][-1] += triangle[l-1][-1]
            n = 1
            while n < count-1:
                triangle[l][n] += min( triangle[l-1][n-1], triangle[l-1][n] )
                n += 1
            l += 1

        return min(triangle[-1])


if __name__ == '__main__':
    print(Solution().minimumTotal([[2],[3,4],[6,5,7],[4,1,8,3]]))
